Skip to content

fix(swift-sdk): fix dash-spv sync (somehow)#3404

Closed
ZocoLini wants to merge 1 commit intov3.1-devfrom
fix/dash-spv-sync
Closed

fix(swift-sdk): fix dash-spv sync (somehow)#3404
ZocoLini wants to merge 1 commit intov3.1-devfrom
fix/dash-spv-sync

Conversation

@ZocoLini
Copy link
Copy Markdown
Collaborator

@ZocoLini ZocoLini commented Mar 25, 2026

Somehow this Pr makes dash-spv work in my machine after clearing the simulator with the changes this PR introduce, I didn't do a deep research on why, I will be investigating tomorrow, I have a little theory and has too do with file permissions and the way FileManager creates directories vs how Rust does. The reason I think thats the issue its bcs sync was working fine for me until I cleared the storage, then it got stuck until I removed the file creation and created a new simulator, letting dash-spv manage the directory creation

Summary by CodeRabbit

  • Refactor
    • Synchronization execution moved from asynchronous to synchronous across the SDK, changing how wallet initialization and data sync are started from apps and UI triggers. This adjusts the sync start call pattern without altering visible sync outcomes.

@github-actions github-actions bot added this to the v3.1.0 milestone Mar 25, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

SPV synchronization methods were made synchronous: SPVClient.startSync() and WalletService.startSync() lost async. WalletService no longer creates the SPV data directory during init/initialization. Call sites (example view) were updated from await/Task to direct synchronous calls.

Changes

Cohort / File(s) Summary
SPV Core
packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVClient.swift
startSync() changed from async throws to throws (removed async). Minor whitespace-only change in destroy().
Wallet Service
packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift
Removed creation of SPV dataDir in initializer and initializeNewSPVClient(). startSync() changed from async to synchronous; calls updated from try await to try, error capture retained.
UI Call Site
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift
Replaced Task { await walletService.startSync() } with direct walletService.startSync() invocation to match synchronous API.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hopped from async to a steady beat,
No more awaiting — my paws tap fleet.
Wallet and SPV now sync in line,
A tidy hop, a shorter time. 🎋

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and non-descriptive, using the phrase '(somehow)' which conveys no meaningful information about what the fix actually does or achieves. Replace the vague title with a specific description of the actual changes, e.g., 'fix(swift-sdk): convert SPV sync from async to synchronous' or similar, based on the actual technical change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dash-spv-sync

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 25, 2026

✅ DashSDKFFI.xcframework built for this PR.

SwiftPM (host the zip at a stable URL, then use):

.binaryTarget(
  name: "DashSDKFFI",
  url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
  checksum: "8b4c7ecfa04d142f8a405085177f6a0877d076adae22f0ac1c738b7b1d945ab0"
)

Xcode manual integration:

  • Download 'DashSDKFFI.xcframework' artifact from the run link above.
  • Drag it into your app target (Frameworks, Libraries & Embedded Content) and set Embed & Sign.
  • If using the Swift wrapper package, point its binaryTarget to the xcframework location or add the package and place the xcframework at the expected path.

@shumkov
Copy link
Copy Markdown
Collaborator

shumkov commented Mar 26, 2026

Heya! I need recent version of dashcore here #3405. I guess it affect what you are doing here

Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Neither proposed finding is verified against the source. The startSync signature change is not a proven source-breaking compile failure in Swift, and the SPV directory regression is only a suspicion because the native FFI directory-creation behavior is not present in this repo for verification.

Reviewed commit: 9f8ec47

@ZocoLini ZocoLini force-pushed the fix/dash-spv-sync branch from 9f8ec47 to f662bc9 Compare March 30, 2026 16:20
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift`:
- Around line 327-329: The call path currently invokes WalletService.startSync()
(which is `@MainActor`) and ultimately SPVClient.startSync() that calls the
synchronous FFI dash_spv_ffi_client_run(), blocking the main thread; fix by
offloading the blocking FFI call to a background queue—either wrap the
spvClient.startSync() invocation inside DispatchQueue.global().async inside
WalletService.startSync() (clearing lastSyncError before dispatch and setting
lastSyncError back on the MainActor on error), or move the
DispatchQueue.global().async into SPVClient.startSync() around the
dash_spv_ffi_client_run() call so that the synchronous FFI never runs on the
main thread. Ensure errors are propagated back to the main actor (e.g., update
lastSyncError on MainActor) and keep caller API unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b167915-df7b-46a9-b21d-a6b78991b740

📥 Commits

Reviewing files that changed from the base of the PR and between 9f8ec47 and f662bc9.

📒 Files selected for processing (3)
  • packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVClient.swift
  • packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift
  • packages/swift-sdk/Sources/SwiftDashSDK/Core/SPV/SPVClient.swift

Comment on lines 327 to 329
private func startSync() {
Task {
await walletService.startSync()
}
walletService.startSync()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== WalletService isolation and startSync body =="
fd -a 'WalletService.swift' | while read -r f; do
  echo "FILE: $f"
  rg -n -C3 '@MainActor|public func startSync\(|spvClient.startSync\(' "$f"
done

echo
echo "== SPVClient startSync and FFI run call =="
fd -a 'SPVClient.swift' | while read -r f; do
  echo "FILE: $f"
  rg -n -C3 'func startSync\(|dash_spv_ffi_client_run' "$f"
done

echo
echo "== Any explicit background offloading around sync start =="
rg -n --type=swift -C2 'Task\.detached|DispatchQueue\.global|withCheckedContinuation|startSync\(' packages/swift-sdk

Repository: dashpay/platform

Length of output: 45226


UI-thread blocking risk: startSync() invokes FFI without background offloading.

Line 328 calls walletService.startSync() directly from the main-thread action path. WalletService.startSync() is @MainActor and invokes spvClient.startSync(), which directly calls the synchronous FFI dash_spv_ffi_client_run() without dispatching to a background queue. This breaks the established SDK pattern: similar heavy FFI operations (e.g., in ShieldedPoolClient, AddressSyncService, ShieldedCryptoService) consistently offload work via DispatchQueue.global().async to prevent main-thread blocking. SPV synchronization is a blocking I/O operation and must be moved off the main thread.

Wrap the FFI call in DispatchQueue.global().async within SPVClient.startSync(), or refactor WalletService.startSync() to dispatch the call asynchronously:

public func startSync() {
    lastSyncError = nil
    DispatchQueue.global().async {
        do {
            try self.spvClient.startSync()
        } catch {
            Task { `@MainActor` in
                self.lastSyncError = error
                print("❌ Sync failed: \($0)")
            }
        }
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift`
around lines 327 - 329, The call path currently invokes
WalletService.startSync() (which is `@MainActor`) and ultimately
SPVClient.startSync() that calls the synchronous FFI dash_spv_ffi_client_run(),
blocking the main thread; fix by offloading the blocking FFI call to a
background queue—either wrap the spvClient.startSync() invocation inside
DispatchQueue.global().async inside WalletService.startSync() (clearing
lastSyncError before dispatch and setting lastSyncError back on the MainActor on
error), or move the DispatchQueue.global().async into SPVClient.startSync()
around the dash_spv_ffi_client_run() call so that the synchronous FFI never runs
on the main thread. Ensure errors are propagated back to the main actor (e.g.,
update lastSyncError on MainActor) and keep caller API unchanged.

@ZocoLini
Copy link
Copy Markdown
Collaborator Author

Everything looks to be working now

@ZocoLini ZocoLini closed this Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants